﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ControleRepresentante.Logic.Models
{
    public abstract class DetailsHolder : AttributeHolder
    {
        private readonly IList<Contato> m_Contatos;
        private readonly IList<Conta> m_Contas;
        private readonly IList<Endereco> m_Enderecos;
        private string m_Cidade;
        private string m_Bairro;
        private string m_EnderecoRua;
        private string m_EnderecoNumero;
        private string m_EnderecoComplemento;
        private string m_EnderecoCEP;
        private string m_EnderecoEstado;
        private string m_ContatoTelefone;
        private string m_ContatoFax;
        private string m_ContatoEmail;
        private string m_ContatoCelular;

        protected DetailsHolder()
        {
            m_Contatos = new List<Contato>();
            m_Enderecos = new List<Endereco>();
            m_Contas = new List<Conta>();
        }

        public virtual IEnumerable<Contato> Contatos { get { return m_Contatos; } }
        public virtual IEnumerable<Endereco> Enderecos { get { return m_Enderecos; } }
        public virtual IEnumerable<Conta> Contas { get { return m_Contas; } }
        public virtual string ContatoFax
        {
            get { return m_ContatoFax ?? (m_ContatoFax = this.GetPrincipalContatoValor(ContatoType.FaxComercial)); }
            set { m_ContatoFax = value; }
        }
        public virtual string ContatoCelular
        {
            get { return m_ContatoCelular ?? (m_ContatoCelular = this.GetPrincipalContatoValor(ContatoType.Celular)); }
            set { m_ContatoCelular = value; }
        }
        public virtual string ContatoTelefone
        {
            get { return m_ContatoTelefone ?? (m_ContatoTelefone = this.GetPrincipalContatoValor(ContatoType.TelefoneComercial)); }
            set { m_ContatoTelefone = value; }
        }
        public virtual string ContatoEmail
        {
            get { return m_ContatoEmail ?? (m_ContatoEmail = this.GetPrincipalContatoValor(ContatoType.Email)); }
            set { m_ContatoEmail = value; }
        }
        public virtual string EnderecoRua
        {
            get { return m_EnderecoRua ?? (m_EnderecoRua = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Rua)); }
            set { m_EnderecoRua = value; }
        }
        public virtual string EnderecoNumero
        {
            get { return m_EnderecoNumero ?? (m_EnderecoNumero = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Numero)); }
            set { m_EnderecoNumero = value; }
        }
        public virtual string EnderecoComplemento
        {
            get { return m_EnderecoComplemento ?? (m_EnderecoComplemento = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Complemento)); }
            set { m_EnderecoComplemento = value; }
        }
        public virtual string EnderecoCEP
        {
            get { return m_EnderecoCEP ?? (m_EnderecoCEP = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.CEP)); }
            set { m_EnderecoCEP = value; }
        }
        public virtual string EnderecoEstado
        {
            get { return m_EnderecoEstado ?? (m_EnderecoEstado = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Estado)); }
            set { m_EnderecoEstado = value; }
        }
        public virtual string EnderecoCidade
        {
            get { return m_Cidade ?? (m_Cidade = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Cidade)); }
            set { m_Cidade = value; }
        }
        public virtual string EnderecoBairro
        {
            get { return m_Bairro ?? (m_Bairro = this.GetPrincipalEnderecoField(EnderecoType.Comercial, x => x.Bairro)); }
            set { m_Bairro = value; }
        }

        public virtual void AddContato(Contato contato)
        {
            m_Contatos.Add(contato);
            contato.DetailsHolder = this;
        }

        public virtual void RemoveContato(Contato contato)
        {
            m_Contatos.Remove(contato);
            contato.DetailsHolder = null;
        }

        public virtual void AddConta(Conta conta)
        {
            m_Contas.Add(conta);
            conta.DetailsHolder = this;
        }

        public virtual void RemoveConta(Conta conta)
        {
            m_Contas.Remove(conta);
            conta.DetailsHolder = null;
        }

        public virtual void AddEndereco(Endereco endereco)
        {
            m_Enderecos.Add(endereco);
            endereco.DetailsHolder = this;
        }

        public virtual void RemoveEndereco(Endereco endereco)
        {
            m_Enderecos.Remove(endereco);
            endereco.DetailsHolder = null;
        }

        public virtual string GetEnderecoFieldString()
        {
            return Endereco.GetEnderecoFieldString(EnderecoRua, EnderecoNumero, EnderecoComplemento);
        }
    }

    internal static class DetailsHolderHelperExtensions
    {
        public static string GetPrincipalContatoValor(this DetailsHolder detailsHolder, ContatoType contatoType)
        {
            Contato contato = detailsHolder.Contatos.FirstOrDefault(x => x.Tipo == contatoType && x.Principal);
            return contato == null ? null : contato.Valor;
        }

        public static string GetPrincipalEnderecoField(this DetailsHolder detailsHolder, EnderecoType enderecoType, Func<Endereco, string> getField)
        {
            Endereco endereco = detailsHolder.GetEnderecoForTipo(enderecoType);
            return endereco == null ? null : getField(endereco);
        }

        public static Endereco GetPrincipalEndereco(this DetailsHolder detailsHolder)
        {
            return detailsHolder.GetEnderecoForTipo(EnderecoType.Comercial) ??
                   detailsHolder.GetEnderecoForTipo(EnderecoType.Residencial) ??
                   detailsHolder.GetEnderecoForTipo(EnderecoType.Outro);
        }

        private static Endereco GetEnderecoForTipo(this DetailsHolder detailsHolder, EnderecoType enderecoType)
        {
            return detailsHolder.Enderecos.FirstOrDefault(x => x.Tipo == enderecoType && x.Principal);
        }
    }
}